/**
 * 
 */
package com.nari.interfaces.handler;

import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.AttributeKey;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;

import com.nari.interfaces.decipher.common.warn.DecipherWarnConstants;
import com.nari.interfaces.decipher.common.warn.DecipherWarnLogger;
import com.nari.interfaces.decipher.gprs.IoSessionRepeatState;
import com.nari.interfaces.decipher.gprs.vo.ClientHost;
import com.nari.interfaces.decipher.gprs.vo.DistributeFrameStateSeal;
import com.nari.interfaces.decipher.gprs.vo.UploadMeterDataSeal;
import com.nari.interfaces.model.IMissionFailureLog;
import com.nari.interfaces.service.IInterfacesHandlerService;
import com.nari.platform.date.CalendarUtils;

/**
 * 
 * @author Xiaopeng
 * @date 2013-11-4
 */
public class InterfacesDataHandler extends IoHandlerAdapter {
	private IInterfacesHandlerService iInterfacesHandlerService;
	//会话状态，AttributeKey可防止键值重复
	private static final AttributeKey session_context = new AttributeKey(InterfacesDataHandler.class, "sessionContext");
	//系统的会话缓存表
	private static Map<Long, IoSessionRepeatState> sessionTable = new ConcurrentHashMap<Long, IoSessionRepeatState>();
	
	/**
	 * 连接建立，开启会话，发送广播帧
	 * @param session
	 * @throws Exception
	 * @author Xiaopeng
	 * @date 2013-11-4
	 */
	public synchronized void sessionOpened(IoSession session) throws Exception {
		super.sessionOpened(session);
		//更新系统的会话缓存表
		if(sessionTable.get(session.getId()) == null) {
			sessionTable.put(session.getId(), IoSessionRepeatState.getInstance(session));
		}
		//客户端主机
		SocketAddress socketAddress = session.getRemoteAddress();
		InetSocketAddress inetAddress = (InetSocketAddress) socketAddress;
		String connectIP = inetAddress.getAddress().getHostAddress();
		int port = inetAddress.getPort();
		ClientHost clientHost = ClientHost.getInstance(connectIP, port);
		System.out.println(">>Client "+clientHost.toString()+" Visit["+CalendarUtils.parseDateTimeToString(new Date())+" Session Created...]");
		//发送广播帧
		distributeServerResponse(session, DistributeFrameStateSeal.serverState_broadcasting);
	}
	
	/**
	 * 
	 * @param session
	 * @param status
	 * @throws Exception
	 * @author Xiaopeng
	 * @date 2013-11-4
	 */
	public synchronized void sessionIdle(IoSession session, IdleStatus status) throws Exception {
		super.sessionIdle(session, status);
		//客户端主机
		SocketAddress socketAddress = session.getRemoteAddress();
		InetSocketAddress inetAddress = (InetSocketAddress) socketAddress;
		String connectIP = inetAddress.getAddress().getHostAddress();
		int port = inetAddress.getPort();
		ClientHost clientHost = ClientHost.getInstance(connectIP, port);
		System.out.println(">>Client "+clientHost.toString()+" Session Idle exceed 10 Minutes["+CalendarUtils.parseDateTimeToString(new Date())+"] Data Buffered...");
		//记录会话状态，支持断点续传
		UploadMeterDataSeal sessionMeterDataSeal = getSessionData(session); //获取会话状态数据
		if(sessionMeterDataSeal != null) {
			iInterfacesHandlerService.saveOrUpdateBufferedMeterDataSeal(sessionMeterDataSeal, clientHost);
		}
		session.close(true);
	}
	
	/**
	 * 
	 * @param session
	 * @throws Exception
	 * @author Xiaopeng
	 * @date 2013-11-4
	 */
	public synchronized void sessionClosed(IoSession session) throws Exception {
		super.sessionClosed(session);
		//清除会话缓存表中已经关闭的会话
		sessionTable.remove(session.getId());
		//客户端主机
		SocketAddress socketAddress = session.getRemoteAddress();
		InetSocketAddress inetAddress = (InetSocketAddress) socketAddress;
		String connectIP = inetAddress.getAddress().getHostAddress();
		int port = inetAddress.getPort();
		ClientHost clientHost = ClientHost.getInstance(connectIP, port);
		System.out.println(">>Client "+clientHost.toString()+" Leave["+CalendarUtils.parseDateTimeToString(new Date())+" Session Closed...]");
	}
	
	/**
	 * 接受来自客户端数据的同时,并将响应数据发送给客户端
	 * @param session
	 * @param message
	 * @throws Exception
	 * @author Xiaopeng
	 * @date 2013-11-4
	 */
	public synchronized void messageReceived(IoSession session, Object message) throws Exception {
		super.messageReceived(session, message);
		//客户端主机
		SocketAddress socketAddress = session.getRemoteAddress();
		InetSocketAddress inetAddress = (InetSocketAddress) socketAddress;
		String connectIP = inetAddress.getAddress().getHostAddress();
		int port = inetAddress.getPort();
		ClientHost clientHost = ClientHost.getInstance(connectIP, port);
		System.out.println(">>Received Handler "+clientHost.toString()+" Data["+CalendarUtils.parseDateTimeToString(new Date())+" Data Received...]");
		//获取客户端发送数据
		UploadMeterDataSeal uploadMeterDataSeal = (UploadMeterDataSeal) message;
		//获取会话状态数据
		UploadMeterDataSeal sessionMeterDataSeal = getSessionData(session);
		//判断解析器数据工作状态
		if(DecipherWarnConstants.warnReport_level_fatal.equals(uploadMeterDataSeal.getDecipherFailureLevel())) {
			//同步上传数据到会话数据中
			sessionMeterDataSeal = ServerMeterDataSealSynchronous.synchroMeterDataSeal(sessionMeterDataSeal, uploadMeterDataSeal);
			//解析器发生致命错误时，记录断点，断开连接，并进行日志审计
			if(sessionMeterDataSeal != null) {
				iInterfacesHandlerService.saveOrUpdateBufferedMeterDataSeal(sessionMeterDataSeal, clientHost);
			}
			session.close(true);
			return;
		}
		//读取上传数据的任务批次
		if(uploadMeterDataSeal.getConcentratorNo()!=null && uploadMeterDataSeal.getRecordTime()!=null) {
			//任务批次对应的集中器号
			String concentratorNo = uploadMeterDataSeal.getConcentratorNo();
			//任务批次对应的抄表日期
			String recordTime = uploadMeterDataSeal.getRecordTime();
			//若只上传一帧数据，存储数据，上传结束
			if(uploadMeterDataSeal.getTotalFrames()==1 && uploadMeterDataSeal.getCurrFrameIndex()==1) {
				//热表数据存档
				iInterfacesHandlerService.saveUploadMeterDatas(uploadMeterDataSeal, clientHost);
				session.close(true);
				return;
			}
			//查询断点上传任务数据
			UploadMeterDataSeal breakoffMeterDataSeal = iInterfacesHandlerService.queryBufferedMeterDataSeal(concentratorNo, recordTime);
			//删除断点缓存数据
			iInterfacesHandlerService.deleteMissionStateDataByMark(concentratorNo, recordTime);
			if(sessionMeterDataSeal == null) { //会话为空：第一次上传或断点续传
				if(breakoffMeterDataSeal == null) { //缓存为空，即为第一次上传
					//检查上传是否为第一帧数据，若不是第一帧，则要求重发数据
					if(uploadMeterDataSeal.getCurrFrameIndex() > 1) {
						uploadMeterDataSeal = ServerMeterDataSealSynchronous.resetMeterDataSeal(uploadMeterDataSeal);
					}
					//设置Session会话数据
					setSessionStateData(session, uploadMeterDataSeal);
					//更新当前的会话缓存表
					refreshSessionTable(session);
				} else { //缓存不为空，断点续传
					//同步断点缓存与上传数据
					breakoffMeterDataSeal = ServerMeterDataSealSynchronous.synchroMeterDataSeal(breakoffMeterDataSeal, uploadMeterDataSeal);
					//设置Session会话数据
					setSessionStateData(session, breakoffMeterDataSeal);
					//更新当前的会话缓存表
					refreshSessionTable(session);
				}
			} else { //会话不为空
				//检查上传数据与会话数据是否同一批次任务
				if(concentratorNo.equals(sessionMeterDataSeal.getConcentratorNo()) 
						&& recordTime.equals(sessionMeterDataSeal.getRecordTime())) {
					//判断上传数据是否为会话数据的下一帧
					if(uploadMeterDataSeal.getCurrFrameIndex() == sessionMeterDataSeal.getCurrFrameIndex()+1) {
						//同步上传数据到会话数据中
						sessionMeterDataSeal = ServerMeterDataSealSynchronous.synchroMeterDataSeal(sessionMeterDataSeal, uploadMeterDataSeal);
					} else { //数据乱帧
						//同步断点缓存（若存在）到上传数据中
						if(breakoffMeterDataSeal != null) {
							uploadMeterDataSeal = ServerMeterDataSealSynchronous.synchroMeterDataSeal(breakoffMeterDataSeal, uploadMeterDataSeal);
							//比较同步数据与会话数据帧状态
							if(uploadMeterDataSeal.getCurrFrameIndex() > sessionMeterDataSeal.getCurrFrameIndex()) {
								sessionMeterDataSeal = uploadMeterDataSeal;
							}
						}
					}
					//设置Session会话数据
					setSessionStateData(session, sessionMeterDataSeal);
					//更新当前的会话缓存表
					refreshSessionTable(session);
				} else { //任务不一致
					//处理当前会话数据
					if(sessionMeterDataSeal.getCurrFrameIndex() == sessionMeterDataSeal.getTotalFrames()) {
						//当前会话数据上传结束，则热表数据存档
						iInterfacesHandlerService.saveUploadMeterDatas(sessionMeterDataSeal, clientHost);
					} else if(sessionMeterDataSeal.getCurrFrameIndex() < sessionMeterDataSeal.getTotalFrames()) {
						//当前会话数据未上传结束，则存储到断点缓存中
						iInterfacesHandlerService.saveOrUpdateBufferedMeterDataSeal(sessionMeterDataSeal, clientHost);
						//下发一次取帧指令
//						distributeServerResponse(session, DistributeFrameStateSeal.serverState_requestData);
					}
					//根据上传数据开启新任务
					if(breakoffMeterDataSeal!=null 
							&& breakoffMeterDataSeal.getCurrFrameIndex()+1==uploadMeterDataSeal.getCurrFrameIndex()) {
						//上传数据是断点缓存数据的下一帧，同步缓存数据到上传数据中
						uploadMeterDataSeal = ServerMeterDataSealSynchronous.synchroMeterDataSeal(breakoffMeterDataSeal, uploadMeterDataSeal);
						//设置Session会话数据
						setSessionStateData(session, uploadMeterDataSeal);
						//更新当前的会话缓存表
						refreshSessionTable(session);
					} else if(uploadMeterDataSeal.getCurrFrameIndex() == 1) {
						//设置Session会话数据
						setSessionStateData(session, uploadMeterDataSeal);
						//更新当前的会话缓存表
						refreshSessionTable(session);
					} else {
						//重置上传数据，要求重发数据
						uploadMeterDataSeal = ServerMeterDataSealSynchronous.resetMeterDataSeal(uploadMeterDataSeal);
						//设置Session会话数据
						setSessionStateData(session, uploadMeterDataSeal);
						//更新当前的会话缓存表
						refreshSessionTable(session);
					}
				}
			}
			//根据要求下一帧的帧序号及总帧数判断会话是否继续
			sessionMeterDataSeal = getSessionData(session);
			if(sessionMeterDataSeal.getRequestFrameIndex() <= sessionMeterDataSeal.getTotalFrames()) {
				//要求客户端发送下一帧数据
				distributeServerResponse(session, DistributeFrameStateSeal.serverState_requestData);
			} else { //数据发送完成
				//热表数据存档
				iInterfacesHandlerService.saveUploadMeterDatas(sessionMeterDataSeal, clientHost);
				session.close(true);
			}
		} else { //上传任务无法识别
			distributeServerResponse(session, DistributeFrameStateSeal.serverState_broadcasting);
			//更新当前的会话缓存表
			refreshSessionTable(session);
		}
	}
	
	/**
	 * 下发服务端帧指令
	 * @param serverFrameSeal
	 * @throws Exception
	 * @author Xiaopeng
	 * @date 2014-3-31
	 */
	public synchronized static void distributeServerResponse(IoSession session, Integer serverState) {
		UploadMeterDataSeal serverFrameSeal = (UploadMeterDataSeal) getSessionData(session);
		//服务器处理反馈结果
		DistributeFrameStateSeal responseFrameSeal = null;
		if(serverState==DistributeFrameStateSeal.serverState_broadcasting.intValue() || 
				serverFrameSeal==null || serverFrameSeal.getConcentratorNo()==null) {
			responseFrameSeal = DistributeFrameStateSeal.getInstance(DistributeFrameStateSeal.serverState_broadcasting, null, 1);
		} else if(serverFrameSeal.getRequestFrameIndex() >  serverFrameSeal.getTotalFrames()) {
			responseFrameSeal = DistributeFrameStateSeal.getInstance(DistributeFrameStateSeal.serverState_communicateFinished, null, null);
		} else {
			responseFrameSeal = DistributeFrameStateSeal.getInstance(DistributeFrameStateSeal.serverState_requestData, serverFrameSeal.getConcentratorNo(), serverFrameSeal.getRequestFrameIndex());
		}
		session.write(responseFrameSeal);
	}
	
	/**
	 * 处理远程连接过程中产生的异常
	 * @param session
	 * @param cause
	 * @throws Exception
	 * @author Xiaopeng
	 * @date 2013-11-4
	 */
	public synchronized void exceptionCaught(IoSession session, Throwable cause) throws Exception {
		try {
//			super.exceptionCaught(session, cause);
//			cause.printStackTrace();
			//客户端主机
			SocketAddress socketAddress = session.getRemoteAddress();
			InetSocketAddress inetAddress = (InetSocketAddress) socketAddress;
			String connectIP = inetAddress.getAddress().getHostAddress();
			int port = inetAddress.getPort();
			ClientHost clientHost = ClientHost.getInstance(connectIP, port);
			//读取回话数据
			UploadMeterDataSeal sessionMeterDataSeal = getSessionData(session);
			if(sessionMeterDataSeal == null) {
				sessionMeterDataSeal = new UploadMeterDataSeal();
			}
			//记录异常日志
			IMissionFailureLog errorLog = DecipherWarnLogger.getMissionLogInstance(DecipherWarnConstants.logger_meterType_con, 
					sessionMeterDataSeal.getConcentratorNo(), sessionMeterDataSeal.getRecordTime(), 
					cause.getMessage(), null);
			sessionMeterDataSeal.getFrameDecoderLogList().add(errorLog);
			//解析器发生致命错误时，记录断点，断开连接，并进行日志审计
			if(sessionMeterDataSeal != null) {
				iInterfacesHandlerService.saveOrUpdateBufferedMeterDataSeal(sessionMeterDataSeal, clientHost);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close(true);
		}
	}
	
	/**
	 * 获取会话IoSession的状态数据
	 * @param session
	 * @return
	 * @author Xiaopeng
	 * @date 2013-11-11
	 */
	public synchronized static UploadMeterDataSeal getSessionData(IoSession session) {
		//获取会话状态
		UploadMeterDataSeal sessionMeterDataSeal = (UploadMeterDataSeal) session.getAttribute(session_context);
		return sessionMeterDataSeal;
	}
	
	/**
	 * 设置会话IoSession的状态数据
	 * @param session
	 * @param sessionMeterDataSeal
	 * @author Xiaopeng
	 * @date 2013-11-11
	 */
	public synchronized static void setSessionStateData(IoSession session, UploadMeterDataSeal sessionMeterDataSeal) {
		session.setAttribute(session_context, sessionMeterDataSeal);
	}
	
	/**
	 * 更新会话缓存表
	 * @param session
	 * @author Xiaopeng
	 * @date 2014-3-30
	 */
	public synchronized static void refreshSessionTable(IoSession session) {
		IoSessionRepeatState sessionState = IoSessionRepeatState.getInstance(session);
		sessionTable.put(sessionState.getSession().getId(), sessionState);
	}
	
	/**
	 * 会话超时无响应，则定时重发指令
	 * @author Xiaopeng
	 * @date 2014-1-14
	 */
	public synchronized void repeatDistributeOrder() {
//		System.out.println(">>Scan Session "+new Date()+",Last["+sessionTable.size()+"] Wait to Upload...");
		for(Iterator<Long> it=sessionTable.keySet().iterator(); it.hasNext();) {
			IoSessionRepeatState sessionState = sessionTable.get(it.next());
			//检查会话是否可用
			boolean ifAvailable = IoSessionRepeatState.sessionAvailable(sessionState);
			if(ifAvailable) {
				//客户端主机
				SocketAddress socketAddress = sessionState.getSession().getRemoteAddress();
				InetSocketAddress inetAddress = (InetSocketAddress) socketAddress;
				String connectIP = inetAddress.getAddress().getHostAddress();
				int port = inetAddress.getPort();
				ClientHost clientHost = ClientHost.getInstance(connectIP, port);
				System.out.println(">>Scan Session["+clientHost+"] Timeout[broadcasting Order...]:"+sessionState.getRemainSentCounter());
				UploadMeterDataSeal sessionData = getSessionData(sessionState.getSession());
				if(sessionData != null) {
					distributeServerResponse(sessionState.getSession(), DistributeFrameStateSeal.serverState_requestData);
				} else {
					distributeServerResponse(sessionState.getSession(), DistributeFrameStateSeal.serverState_broadcasting);
				}
			} 
		}
	}
	
	/**
	 * @return the iInterfacesHandlerService
	 */
	public IInterfacesHandlerService getiInterfacesHandlerService() {
		return iInterfacesHandlerService;
	}

	/**
	 * @param iInterfacesHandlerService the iInterfacesHandlerService to set
	 */
	public void setiInterfacesHandlerService(
			IInterfacesHandlerService iInterfacesHandlerService) {
		this.iInterfacesHandlerService = iInterfacesHandlerService;
	}
	
}
